/***************************************************************************
													expr.cpp  -  description
														-------------------
		begin                : Tue Aug 27 2002
		copyright            : (C) 2002 by Michiel Visser
		email                : 
***************************************************************************/

/***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
***************************************************************************/

#include "expr.h"

#ifdef DEBUGLOGGING
#define LOG_EXPR session.log(this)
#else
#define LOG_EXPR
#endif

namespace Expression
{
///.{

#define DEFPT(e) void e::printTyle() const { printf(#e); }

void Expr::evaluateToVoid()
{ 
	Object::Holder oh;
	evaluateToCopy(oh);
}
void CodeComponent::evaluateToCopy(void *space)
{	evaluateToOriginal()->duplicateIn(space); // assume evaluateToOriginal never returns orphan
}
Object *CodeComponent::evaluateToOriginal() // this is the only version of this function that will create orphan. TODO: can be removed? Could this simplify garbage collection? at least simplifying not needing childrenpainters
{ return evaluateToCopy();
}
void ConstExpr::evaluateToCopy(void *space)
{ 
	session.m_curTypePtr=0;
	m_val->duplicateIn(space); //todo: check const expr does not apply to any sub & or #x
}
Object *SharedLiteralExpr::evaluateLiteralToCopy(void)
{ 
	session.m_curTypePtr=0;
	return session.m_sharedLiteralObjects[m_index];
}

void SharedLiteralExpr::toArray(OList::P array) const {
	ADDSTR("#");
	char s[14];
	sprintf(s,"%i ",m_index+1);
	ADDSTR(s);
}

void SharedLiteralExprAssigned::toArray(OList::P array) const {
	OList::P b=array;
	EPtr e = (*session.m_curSharedLiterals)[m_index];
	_ASSERT(!!e);
	ADDSTR("= ");
	ADDA(e->toArrayObject());
	SharedLiteralExpr::toArray(b);
}

bool CodeComponent::isArgumentList() const { return false; }
bool ArgumentListExpr::isArgumentList() const { return false; }

void SharedLiteralsScopeExpr::toArray(OList::P array) const {
	session.m_curSharedLiterals = &m_sharedLiterals;
	m_child->toArray(array);
}

SharedLiteralsScopeExpr::SharedLiteralsScopeExpr(EPtr c, vector<EPtr> &sos): m_child(c)
{
	m_sharedLiterals.swap(sos);
}

void SharedLiteralsScopeExpr::init(void)
{
	//_TVAR(i,m_sharedLiterals.size());
	session.m_sharedLiteralObjects.growByRealloc(m_sharedLiterals.size());
	int i=m_sharedLiterals.size();
	while(--i>=0) {
		if (m_sharedLiterals[i]!=0) {
			//session.m_sharedLiteralExpressions[i] = m_sharedLiterals[i];
			session.m_sharedLiteralObjects[i] = m_sharedLiterals[i]->evaluateToCopy();
		}
	}
}

void SharedLiteralsScopeExpr::finish(void)
{
	session.m_sharedLiteralObjects.erase();
}

Object *ReferenceExpr::evaluateLiteralToCopy()
{
	Object *o=ao();
	new (o)  RefObject(a->evaluateLiteralToCopy());
	return o; 
}

void SharedLiteralsScopeExpr::evaluateToCopy(void *space) { init(); m_child->evaluateLiteralToCopy(space); finish(); }

void CodeComponent::evaluateLiteralToCopy(void *space)  { _ASSERT(0); } //should never happen
Object *CodeComponent::evaluateLiteralToCopy()  { Object *o=ao(); evaluateLiteralToCopy(o); return o;}

///.}

Object *ConstExpr::evaluateLiteralToCopy()
{
	return CodeComponent::evaluateToCopy();
}

IFDEBUG(void UniExprClass::printTyle() const { printf("%s",(char *)tokenString()); a->printTyle(); } )

void UniExprClass::toArray(OList::P array) const {
	ADDSTR(tokenString());
	ADDA(a->toArrayObject(levelLeft()));
}

String UniExprClass::tokenString() const {
	char s[5]; int pos=0;
	for(unsigned int i=token(); i!=0; i>>=8) s[pos++]=(char)i;
	s[pos]=0;
	return s;
}

IFDEBUG(void BinaryExprClass::printTyle() const { this->a->printTyle(); printf("%s",(char *)this->token()); b->printTyle(); } )
void BinaryExprClass::toArray(OList::P array) const {
	ADDA(a->toArrayObject(levelLeft()));
	ADDSTR(tokenString());
	ADDA(b->toArrayObject(levelRight()));
}

void CodeComponent::iterate(void (*callback)(EPtr &e, void *param), void *param) {
}

void UniExprClass::iterate(void (*callback)(EPtr &e, void *param), void *param) {
	callback(a,param);
}

void BinaryExprClass::iterate(void (*callback)(EPtr &e, void *param), void *param) {
	callback(a,param);
	callback(b,param);
}

void SwitchOnExpr::iterate(void (*callback)(EPtr &e, void *param), void *param) {
	callback(a,param);
	FOREACH(EList, m_choices, i)
		if (!!*i) callback(*i,param);
}

void EListExpr::iterate(void (*callback)(EPtr &e, void *param), void *param){
	FOREACH(EList, m_elements, i)
		if (!!*i) callback(*i,param);
}

void CodeComponent::toExprArray(OList::P array) const
{
	ADDSTR("? ");
	ADDA(toArrayObject(levelModify));
}

void FuncExpr::toExprArray(OList::P array) const
{
	ADDSTR(toTyle());
}

CodeComponent::~CodeComponent() {}

//todo: remove
void CodeComponent::doStackOperation(void *space, Object *var, TypeVar s)
{ session.pushStack(var,s);
	evaluateToCopy(space);
	session.popStack();
}

#define DEF_T(name) void name##Expr::evaluateToCopy(void *space)
DEF_T(Negate     ) 
{ {
		Object::Holder oha;
		a->evaluateToPersistCopy(oha);
		oha->valueCopy(space);
		((Object *)space)->negate(); 
	}
	session.m_curTypePtr = 0;
}
DEF_T(Inverse    ) { Object::Holder oha; a->evaluateToCopy(oha); new (space)  IntegerObject(!oha->toInt()); session.m_curTypePtr = 0;}
DEF_T(Length     ) { Object::Holder oha; a->evaluateToCopy(oha); new (space)  IntegerObject(oha->length()); session.m_curTypePtr = 0;}
DEF_T(Type       ) { Object::Holder oha; a->evaluateToCopy(oha); new (space)  IntegerObject(oha->getTypeNum()); session.m_curTypePtr = 0;}
DEF_T(BitNot     ) 
{ { Object::Holder oha; a->evaluateToPersistCopy(oha); oha->valueCopy(space); 
		((Object *)space)->bitNot();  
	}
	session.m_curTypePtr = 0;
}
DEF_T(Describe   ) 
{ 
	EPtr e; 
	Object *o=a->evaluateToPersistCopy();
	new (space)  ExprObject(o->makeExpr());
	session.m_curTypePtr = 0;
}
DEF_T(Value      ) 
{ 
	Object::Holder oha; a->evaluateToCopy(oha); oha->valueCopy(space); 
}
DEF_T(Reference  ) { new (space)  RefObject(a->evaluateToOriginal()); }

Object *DeReferenceExpr::evaluateToOriginal() 
{ 
	return a->evaluateToOriginal()->deReference();
}
void DeReferenceExpr::evaluateToCopy(void *space)
{
	Object::Holder oa;	
	a->evaluateToCopy(oa);
	Object *d(oa->deReference());
	d->duplicateIn(space);
}

Object *      ValueExpr::evaluateToOriginal() 
{ 
	return a->evaluateToOriginal()->value(); 
}

inline void RemoveAt(void *space, Object *a, Object *b)   { a->removeAt(b,space); }
inline void ShiftLeft(void *space, Object *a, Object *b)  { a->shiftLeft(b,space); }
inline void ShiftRight(void *space, Object *a, Object *b) { a->shiftRight(b,space); }
inline void Sub(void *space, Object *a, Object *b)        { new (space) IntegerObject(a->sub(b)?1:0); }
inline void Mul(Object *a, Object *b)        { a->mul(b); }
inline void Add(Object *a, Object *b)        { a->add(b); }
inline void Prepend(Object *a, Object *b)    { a->prepend(b);}
inline void Mod(Object *a, Object *b)
{ if (a->mod(b))
	{	ChildrenPainter cpb(b);
		session.reportRuntimeError("Modulation by zero."); 
	}
}
inline void Div(Object *a, Object *b)
{ if(!a->div(b)) 
	{	ChildrenPainter cpb(b);
		session.reportRuntimeError("Division by zero."); 
	}
}

inline void Equal(void *space, Object *a, Object *b)      { new (space) IntegerObject(*a==b?1:0); }
inline void Unequal(void *space, Object *a, Object *b)    { new (space)  IntegerObject(*a!=b?1:0); }
inline void Smaller(void *space, Object *a, Object *b)      { new (space)  IntegerObject(a->compare(b)<0); }
inline void SmallerEqual(void *space, Object *a, Object *b) { new (space)  IntegerObject(a->compare(b)<=0); }
inline void Greater(void *space, Object *a, Object *b)       { new (space)  IntegerObject(a->compare(b)>0); }
inline void GreaterEqual(void *space, Object *a, Object *b)  { new (space)  IntegerObject(a->compare(b)>=0); }
inline void BitAnd(Object *a, Object *b)  { a->bitAnd(b);}
inline void BitOr(Object *a, Object *b)   { a->bitOr(b);}
inline void BitXor(Object *a, Object *b)  { a->bitXor(b);}
#define DEF_EVAL_OF_EXEC(F) \
void F##Expr::evaluateToCopy(void *space) { \
	ChildrenPainter cp;\
	{	{	Object::Holder oha;\
			a->evaluateToCopy(oha);\
			oha->valueCopy(space);\
			cp.set((Object *)space); \
		} \
		Object::Holder ohb;\
		{	Object::Holder ohr;\
			b->evaluateToCopy(ohb);\
			F(ohr,(Object *)space,ohb); \
		}\
	}\
	session.m_curTypePtr=0;\
} \
void F##AssignExpr::evaluateToCopy(void *space) { \
	Object *oha(a->evaluateToOriginal());\
	{	ChildrenPainter cpa(oha); \
		{	Object::Holder ohb;\
			b->evaluateToCopy(ohb);\
			F(space, oha, ohb); \
		}\
	}\
	session.m_curTypePtr = 0;\
}

#define DEF_EVAL_OF_VOID_EXEC(F) \
void F##Expr::evaluateToCopy(void *space) \
{ ChildrenPainter cp; \
	{ {	Object::Holder oha;\
			a->evaluateToCopy(oha);\
			oha->valueCopy(space); \
			cp.set((Object *)space); \
		}\
		Object::Holder ohb; \
		b->evaluateToCopy(ohb);\
		F((Object *)space,ohb); \
	} \
	session.m_curTypePtr = 0; \
} \
void F##AssignExpr::evaluateToCopy(void *space) \
{ evaluateToVoid(); new (space) NullObject(); \
}\
void F##AssignExpr::evaluateToVoid() \
{ Object *oha(a->evaluateToOriginal());\
	{	SelfPainter cpa(oha); \
		{	Object::Holder ohb;\
			b->evaluateToCopy(ohb);\
			F(oha,ohb); \
		}\
	} \
}

// this one must never return childs of operands:
#define DEF_EVAL_OF_CALC(F) \
void F##Expr::evaluateToCopy(void *space) \
{ Object::HolderCP oha;\
	a->evaluateToCopy(oha);\
	{	Object::Holder ohb;\
		oha.protectChilds(); \
		{	b->evaluateToCopy(ohb);\
			F(space, oha, ohb);\
		}\
	} \
	session.m_curTypePtr = 0; \
}

DEF_EVAL_OF_VOID_EXEC(BitAnd)
DEF_EVAL_OF_VOID_EXEC(BitOr)
DEF_EVAL_OF_VOID_EXEC(BitXor)
DEF_EVAL_OF_VOID_EXEC(Mul)
DEF_EVAL_OF_VOID_EXEC(Add)
DEF_EVAL_OF_VOID_EXEC(Prepend)
DEF_EVAL_OF_VOID_EXEC(Mod)
DEF_EVAL_OF_VOID_EXEC(Div)

DEF_EVAL_OF_EXEC(RemoveAt)
DEF_EVAL_OF_EXEC(ShiftLeft)
DEF_EVAL_OF_EXEC(ShiftRight)
DEF_EVAL_OF_EXEC(Sub)
DEF_EVAL_OF_CALC(Equal)
DEF_EVAL_OF_CALC(Unequal)
DEF_EVAL_OF_CALC(Smaller)
DEF_EVAL_OF_CALC(SmallerEqual)
DEF_EVAL_OF_CALC(Greater)
DEF_EVAL_OF_CALC(GreaterEqual)

void FindIndexExpr::evaluateToCopy(void *space)
{
	Object::HolderCP oha;
	a->evaluateToCopy(oha);
	{	oha.protectChilds();
		{	Object::Holder ohb;
			b->evaluateToCopy(ohb);
			oha->findIndex((Object *)ohb,space); // finished?? todo: fix problem with findindex (see implementation)
		}
	}
	// m_curTypePtr is already set by findIndex
}

void InsertAtExpr::evaluateToCopy(void *space)
{ 
	ChildrenPainter cp;
	{
		{	Object::Holder oha;
			a->evaluateToCopy(oha);
			oha->valueCopy(space);
			cp.set((Object *)space); // prevent children of result to disappear when ohb is released. do this whenever subexpressions can be encapsulated in result
		}
		Object::Holder ohb;
		b->evaluateToCopy(ohb);
		((Object *)space)->insertAt(ohb,NullObject::obj());
	}
	session.m_curTypePtr = 0;
}

Object *InsertAtAssignExpr::evaluateToOriginal() 
{ Object *r;
	SelfPainter cpr;
	{	Object *oha(a->evaluateToOriginal());
		TypeVar *p = session.m_curTypePtr;
		{	SelfPainter cpa(oha);
			{	Object::Holder ohb;
				b->evaluateToCopy(ohb);
				r=NullObject::obj();
				cpr.set(r);
				oha->insertAt(ohb,r);
			}
		}
		session.m_curTypePtr = p;
	}
	return r;
}

void InsertAtAssignExpr::evaluateToVoid() {
	Object *oha(a->evaluateToOriginal());
	{	
		SelfPainter cpa(oha);
		{	
			Object::Holder ohb;
			b->evaluateToCopy(ohb);
			oha->insertAt(ohb,NullObject::obj());
		}
	}
}

void AndExpr::evaluateToCopy(void *space)
{
	a->evaluateToCopy(space);
	if (((Object *)space)->toInt()) {
		((Object *)space)->~Object();
		b->evaluateToCopy(space);
	}
	session.m_curTypePtr = 0;
}

void OrExpr::evaluateToCopy(void *space)
{ a->evaluateToCopy(space);
	if (!((Object *)space)->toInt())
	{	((Object *)space)->~Object();
		b->evaluateToCopy(space);
	} 
	session.m_curTypePtr = 0;
}

void AndAssignExpr::evaluateToVoid()
{ 
	Object *ao(a->evaluateToOriginal());
	if (ao->toInt() )
	{ ((Object *)ao)->~Object();
		b->evaluateToCopy(ao);
	}
}

void OrAssignExpr::evaluateToVoid()
{ Object *ao(a->evaluateToOriginal());
	if (!ao->toInt() )
	{ ((Object *)ao)->~Object();
		b->evaluateToCopy(ao);
	} 
}

void AndAssignExpr::evaluateToCopy(void *space) { evaluateToVoid(); new (space) NullObject(); }
void OrAssignExpr::evaluateToCopy(void *space) { evaluateToVoid(); new (space) NullObject(); }
void InsertAtAssignExpr::evaluateToCopy(void *space) {	evaluateToVoid(); new (space) NullObject(); } 
void SwitchOnExpr::evaluateToCopy(void *space)
{ int i;
	{	Object::Holder oha;
		a->evaluateToCopy(oha);
		i=((Object *)oha)->toInt() + 1;
	}
	EPtr *o=m_choices.pnext(i);
	if (o && !!*o) { 
	IFDEBUGDEEP( (*o)->printTyle(); )
		(*o)->evaluateToCopy(space);//: NullObject::obj();
	}
	else if (!!*m_choices && ( i>1 || !!m_choices.next() ) ) {
		IFDEBUGDEEP( (*m_choices)->printTyle(); )
		(*m_choices)->evaluateToCopy(space);
	}
	else new (space) NullObject();
}

IFDEBUG( 
void SwitchOnExpr::printTyle() const { printf("SwitchOn: "); a->printTyle(); }
)

void SwitchOnExpr::toArray(OList::P array) const
{ 
	ADDA(a->toArrayObject(levelSwitch));
	ADDSTR(" ? ");
	bool first=true;
	FOREACH(EList, m_choices, i)
	{ if (first) first=false; 
		else ADDSTR(" : ");
		if (!!*i) 
		{	ADDA( (*i)->toArrayObject(levelSwitch) );
		}
	}
}

void ListExpr::evaluateToCopy(void *space)
{ 
	ChildrenPainter cp;
	IFDEBUGDEEP(printf("{\n");)
	{
		OList::P resi(&(new (space) ListObject())->getEditableListQuick());
		cp.set((Object *)space);
		FOREACH(EList, m_elements, i)	{ 
			IFDEBUGDEEP( printf("le:  "); i->printTyle(); printf("\n"); )
			resi->prepend((*i)->evaluateToPersistCopy());
			resi++;
		}
	}
	IFDEBUGDEEP(printf("}\n");)
}

void SequenceExpr::evaluateToCopy(void *space)
{ 
	ChildrenPainter cp;
	IFDEBUGDEEP(printf("(\n");)
	{
		FOREACH(EList, m_elements, i) { 
			if (!i.next())
				(*i)->evaluateToCopy(space);
			else
				(*i)->evaluateToVoid();
		}
	}
	IFDEBUGDEEP(printf(")\n");)
}


void ListExpr::evaluateLiteralToCopy(void *space) // only for constants!
{
	OList::P resi(&(new (space) ListObject())->getEditableListQuick());
	FOREACH(EList, m_elements, i) { 
		resi->prepend((*i)->evaluateLiteralToCopy()); 
		resi++;
	}
}

IFDEBUG( DEFPT(ListExpr)  )

void ListExpr::toArray(OList::P array) const
{ 
	ADDSTR("[ ");
	toArgumentsArray(array);
	ADDSTR(!m_elements?"]":" ]");
}
MultiStat::~MultiStat() { if (!!m_queue) ((LocalVarVectorQueue &)*m_queue).erase() ; }

void MultiStat::evaluateToVoid()
{
	push();
	FOREACH(EList, m_elements, i) {
		IFDEBUGDEEP( printf("void:  "); (*i)->printTyle(); printf("\n"); )
		(*i)->evaluateToVoid();
		if (session.m_flow.state)
			break;
	}
	pop();
}

void MultiStat::evaluateToCopy(void *space) //to be used in a~b, but not in a~:b
{
	evaluateToVoid();
	bool handleFlowNow = session.m_flow.state!=Session::flow_run && session.m_flow.state!=Session::flow_exception && session.m_flow.state!=Session::flow_return;
	if (handleFlowNow && session.m_flow.hasResult)
		session.m_flow.result.memCopyTo(space);
	else
		new (space) NullObject();
	if (handleFlowNow)
		session.m_flow.state=Session::flow_run;
}

void FlowChangerWithResultStatement::evaluateToVoid() {
	m_result->evaluateToCopy(session.m_flow.result);
	session.m_flow.hasResult = true;
	session.m_flow.state = m_newState;
}

void FlowChangerWithoutResultStatement::evaluateToVoid() {
	session.m_flow.hasResult = false;
	session.m_flow.state = m_newState;
}

void FlowChangerWithoutResultStatement::toArray(OList::P array) const {
	switch(session.m_flow.state) {
	case Session::flow_continueOrReturn: ADDSTR("=>"); return;
	case Session::flow_break: ADDSTR("=>>"); return;
	case Session::flow_return: ADDSTR("=>>>"); return;
	case Session::flow_exception: ADDSTR("=!>"); return;
	}
}

void FlowChangerWithResultStatement::toArray(OList::P array) const {
	m_result->toArray(array);
	FlowChangerWithoutResultStatement::toArray(array);
}


void CatchExpr::evaluateToVoid() {
	a->evaluateToVoid();
	if (session.m_flow.state==Session::flow_exception) {
		session.pushStack(session.m_flow.result->copy()); //todo: persist?
		b->evaluateToVoid();
	}
}

void FinallyExpr::evaluateToVoid() {
	a->evaluateToVoid();
	Session::FlowState os=session.m_flow.state;
	bool ohs=session.m_flow.hasResult;
	if (os) {
		if (ohs) {
			Object::HolderNotDeleting rh;
			session.m_flow.result.memCopyTo(rh);
			ChildrenPainter cp;
			cp.set((Object *)rh);
			b->evaluateToVoid();//just always execute this, regardless of situation of a.
			if (session.m_flow.state && session.m_flow.hasResult) {
				session.m_flow.result->~Object();
				rh.memCopyTo(session.m_flow.result);
			}
		}
		session.m_flow.state=os;
	} else
		b->evaluateToVoid();
}

void FinallyExpr::evaluateToCopy(void *space) { //this only happens in the a~{b}<==c scenario I think
	a->evaluateToCopy(space);
	ChildrenPainter cpr((Object *)space);
	Session::FlowState os=session.m_flow.state;
	bool ohs=session.m_flow.hasResult;
	if (os) {
		if (ohs) {
			Object::HolderNotDeleting rh;
			session.m_flow.result.memCopyTo(rh);
			ChildrenPainter cp((Object *)rh);
			b->evaluateToVoid();//just always execute this, regardless of situation of a.
			if (session.m_flow.state && session.m_flow.hasResult) {
				session.m_flow.result->~Object();
				rh.memCopyTo(session.m_flow.result);
			}
		}
		session.m_flow.state=os;
	} else
		b->evaluateToVoid();
}

IFDEBUG( DEFPT(SequenceExpr)  )

void SequenceExpr::toArray(OList::P array) const { 
	_ASSERT(!!m_elements); // should never happen, null is const expr
	ADDSTR("( ");
	bool first=true;
	FOREACH(EList, m_elements, i) {
		if (first) first=false; else ADDSTR(", ");
		ADDA((*i)->toArrayObject());
	}
	if (first) ADDSTR(first?")":" )");
}


void MultiStat::toArray(OList::P array) const { 
	_ASSERT(!!m_elements); // should never happen, null is const expr
	ADDSTR("{ ");
	FOREACH(EList, m_elements, i) {
		ADDA((*i)->toArrayObject());
		ADDSTR("; ");
	}
	ADDSTR("}");
}

bool CodeComponent::isSingleResult() const
{
	return true;
};

bool FlowChangerWithResultStatement::isSingleResult() const {
	return m_newState!=Session::flow_continueOrReturn;
}

bool MultiStat::isSingleResult() const {
	FOREACH(EList, m_elements, i) {
		if (!(*i)->isSingleResult())
			return false;
	}
	return true;
}


void ActOnMultiExpr::evaluateToCopy(void *space)
{
	if (session.m_flow.state) { new (space) NullObject(); return; }
	Ptr<ObjectIterator>::Own::NoCopy oi;
	if (!!a) {
		Object::Holder oha;
		a->evaluateToPersistCopy(oha);
		if (session.m_flow.state) { new (space) NullObject(); return; }
		oi = oha->getIterator();
	} else {
		oi = new CountingObjectIterator();
	}
	if (m_singleResult) {
		for(;!oi->hasFinished();oi->next()) {
			oi->pushStack();
			//session.pushStack(oi->getKey(),oi->getKeyType());
			//session.pushStack(oi->getValue,s);
			b->evaluateToVoid();
			oi->popStack(); //make inline
			//session.popStack();
			//session.popStack();
			switch(session.m_flow.state) {
			case 0: break;
			default: _ASSERT(0); break;
			case Session::flow_exception:
			case Session::flow_return:
				new (space) NullObject();
				goto finish;				
			case Session::flow_break:
				_ASSERT(session.m_flow.hasResult);
				session.m_flow.result.memCopyTo(space);
				session.m_flow.state=Session::flow_run;
				goto finish;
			}
		}
	} else {
		OList::P resi(&(new (space) ListObject())->getEditableListQuick());
		ChildrenPainter cpr((Object *)space);
		{ 
			//example code for list
			if (m_subIsExpression) {
			//} else {
				for(;!oi->hasFinished();oi->next()) {
					Object::HolderNotDeleting oh;
					oi->pushStack();
					b->evaluateToCopy(oh);
					oi->popStack();
					if (session.m_flow.state!=Session::flow_run) {
						oh->~Object();
						_ASSERT_EQUAL(session.m_flow,Session::flow_exception);
						goto finish;
					}
					Object::insertConditionally(oh,resi);
				}
			} else {
				for(;!oi->hasFinished();oi->next()) {
					oi->pushStack();
					b->evaluateToVoid();
					oi->popStack();
					switch(session.m_flow.state) {
					case 0: break;
					default: _ASSERT(0); break;
					case Session::flow_return:
						goto finish;
					case Session::flow_exception:
						goto finish;
					case Session::flow_break:
					case Session::flow_continueOrReturn:
						if (session.m_flow.hasResult) {
							Object *o=ao(); session.m_flow.result.memCopyTo(o); o->persist(); resi->prepend(o); resi++;
						}
						session.m_flow.state=Session::flow_run;
						if (session.m_flow.state==Session::flow_continueOrReturn)
							goto finish;
						break;
					}
				}
			}
		}
	}
finish:
	session.m_curTypePtr=0;
	objectGC.checkGarbage();
}

void ActOnColumnsExpr::evaluateToCopy(void *space)
{
	//TODO: put code here of list::actOnColumns
	OList::P resi(&(new (space) ListObject())->getEditableListQuick());
	ChildrenPainter cpr((Object *)space);
	{ 
		Object::HolderCP oha;
		a->evaluateToPersistCopy(oha);
		oha.protectChilds();
		oha->actOnColumns(resi,b);
	}
	session.m_curTypePtr=0;
	objectGC.checkGarbage();
}

#if _DEBUG_ENABLE==1
#define CHECKGARBAGE_ON_CALL
#endif
void ApplyExpr::evaluateToCopy(void *space)
{
	{
		Object::HolderCP ohb;
		b->evaluateToCopy(ohb);
		TypeVar *oldType = session.m_curTypePtr;
		ohb.protectChilds();
		ohb->apply(a,space);
		session.m_curTypePtr = oldType;
	}
	
	bool handleFlowNow = session.m_flow.state!=Session::flow_exception;
	if (session.m_flow.state!=Session::flow_run && session.m_flow.state!=Session::flow_exception) {
		if (session.m_flow.hasResult)
			session.m_flow.result.memCopyTo(space);
		else
			new (space) NullObject();
		session.m_flow.state=Session::flow_run;
	}
#ifdef CHECKGARBAGE_ON_CALL
	ChildrenPainter cpr((Object *)space);
	objectGC.checkGarbage(); 
#endif
}

void ApplyExpr::evaluateToVoid()
{
	{
		Object::HolderCP ohb;
		b->evaluateToCopy(ohb);
		ohb.protectChilds();
		ohb->applyToVoid(a);
	}
	if (session.m_flow.state!=Session::flow_run && session.m_flow.state!=Session::flow_exception) {
		if (session.m_flow.hasResult)
			session.m_flow.result->~Object();
		session.m_flow.state=Session::flow_run;
	}

#ifdef CHECKGARBAGE_ON_CALL
	objectGC.checkGarbage(); 
#endif
}

inline void transferType(TypeVar *t) {
	if (t && !*t && session.m_curTypePtr && !!*session.m_curTypePtr)
		*t = *session.m_curTypePtr;
}
void AssignmentExpr::evaluateToCopy(void *space)
{
	Object *ar(a->evaluateToOriginal());
	{
		TypeVar *t=session.m_curTypePtr;
		SelfPainter arp(ar);
		{	
			Object::Holder ohb;
			b->evaluateToPersistCopy(ohb);
			ar->set(ohb);
		}
		ar->duplicateIn(space);
		transferType(t);
		session.m_curTypePtr = t;
	}
}

void AssignmentExpr::evaluateToVoid()
{ 
	Object *ar(a->evaluateToOriginal());
	{
		TypeVar *t=session.m_curTypePtr;
		SelfPainter arp(ar);
		{	
			Object::Holder ohb;
			b->evaluateToPersistCopy(ohb);
			ar->set(ohb);
		}
		transferType(t);
	}
}

void ActOnExpr::evaluateToCopy(void *space)
{ 
	Object *ao(a->evaluateToPersistCopy());
	if (session.m_flow.state) { new (space) NullObject(); return; }
	{	
		SelfPainter spa(ao);
		b->doStackOperation(space, ao, session.getCurType() ); 
	}
#ifdef CHECKGARBAGE_ON_CALL
	ChildrenPainter cpr((Object *)space);
	objectGC.checkGarbage(); 
#endif
}

void ActOnExpr::evaluateToVoid()
{ 
	Object *ao(a->evaluateToPersistCopy());
	if (session.m_flow.state) return;
	{	
		SelfPainter spa(ao);
		session.pushStack(ao, session.getCurType());
		b->evaluateToVoid();
		session.popStack();
	}
}

String CodeComponent::toTyle() const
{ 
	Object::Holder oh;
	toArrayObject(oh);
	return oh->toString();
}
IFDEBUG( DEFPT(CodeComponent) )
void CodeComponent::toArray(OList::P array) const {_ASSERT(0);}
void CodeComponent::toArrayObject(void *space) const
{	
	OList ol;
	toArray(&ol);
	new (space) ListObject(ol);
}

Object *CodeComponent::toArrayObject() const
{ 
	Object *p=ao(); toArrayObject(p); return p; 
}

Object *CodeComponent::toArrayObject(int parentlevel) const
{
	OList ol;
	toArray(&ol);
	Object *o=NEW_OBJ ListObject(ol);
	if (levelLeft()>parentlevel)
	{
		OList pol;
		pol.prepend(NEW_OBJ StringObject(" )"));
		pol.prepend(o);
		pol.prepend(NEW_OBJ StringObject("( "));
		return NEW_OBJ ListObject(pol);
	}
	return o;
}

IFDEBUG( DEFPT(ConstExpr) )
void ConstExpr::toArray(OList::P array) const
{ m_val->toArray(array);
}

Object *ArgumentListExpr::evaluateToOriginal()
{
	StackVar &v=session.getStackVar(m_depth);
	session.m_curTypePtr = v.m_typePtr;
	return v.val;
}

Object *ArgumentExpr::evaluateToOriginal()
{
	StackVar &v=session.getStackVar(m_depth);
	session.m_curTypePtr = v.m_typePtr;
	return v.val->index(m_index);
}

Object *IteratorVarExpr::evaluateToOriginal()
{
	LOG_EXPR;
	StackVar &v=session.getStackVar(0);
	session.m_curTypePtr = v.m_typePtr;
	return v.val;
}

Object *IteratorKeyVarExpr::evaluateToOriginal()
{
	StackVar &v=session.getStackVar(1);
	session.m_curTypePtr = v.m_typePtr;
	return v.val;
}

void ArgumentExpr::toArray(OList::P array) const
{
	char s[4];
	sprintf(s,"$%i",m_index);
	ADDSTR(s);
}

void ArgumentListExpr::toArray(OList::P array) const
{
	ADDSTR("$$");
}

void IteratorVarExpr::toArray(OList::P array) const
{
	ADDSTR("$");
}

void CodeComponent::toArgumentsArray(OList::P &array) const {
	ADDSTR("= ");
	ADDA(toArrayObject());
}
/* can this be thrown away
void AddExpr::toArgumentsArray(OList::P &array) const {
	a->toArgumentsArray();
	ADDSTR(", ");
	b->toArgumentsArray();
}
*/

void ListExpr::toArgumentsArray(OList::P &array) const {
	bool first=true;
	FOREACH(EList, m_elements, i) {
		if (first) first=false; else ADDSTR(", ");
		ADDA((*i)->toArrayObject());
	}
}

void ConstExpr::toArgumentsArray(OList::P &array) const {
	if (m_val->getTypeNum()==TOT_List) {
		bool start=true;
		FOREACH(OList,m_val->getList(),i) {
			if (start) start=false; else ADDSTR(", ");
			ADDA((*i)->toArrayObject());
		}
	}
	else
		CodeComponent::toArgumentsArray(array);
}

void IteratorKeyVarExpr::toArray(OList::P array) const
{
	ADDSTR("$#");
}
IFDEBUG(void ApplyExpr::printTyle() const { 
	this->b->printTyle(); printf("("); this->a->printTyle(); printf(")");
})
void ApplyExpr::toArray(OList::P array) const
{	
	ADDA(b->toArrayObject(levelTop));
	if (a->isArgumentList()) {
		ADDSTR("! ");
	}
	else if ( a->levelLeft()!=levelTop )
	{	OList ol;
		ol.prepend(NEW_OBJ StringObject(" )"));
		ol.prepend(a->toArrayObject());
		ol.prepend(NEW_OBJ StringObject("( "));
		ADDA(NEW_OBJ ListObject(ol));
	}
	else
		ADDA(a->toArrayObject());
}

IFDEBUG( DEFPT(StructNameExpr) )
void StructNameExpr::toArray(OList::P array) const
{	
	ADDA(a->toArrayObject(levelTop));
	ADDSTR("[]");
}
void StructNameExpr::evaluateToCopy(void *space)
{
	{
		Object::Holder oh;
		a->evaluateToCopy(oh); // not to void, because void does keep type
	}
	TypeVar p(session.getCurType());
	if (!p) new (space) NullObject();
	else new (space) StringObject(p->m_name);
}
IFDEBUG( DEFPT(StructElemsExpr) )
void StructElemsExpr::toArray(OList::P array) const
{	
	ADDA(a->toArrayObject(levelTop));
	ADDSTR(".*");
}
void StructElemsExpr::evaluateToCopy(void *space)
{
	{
		Object::Holder oh;
		a->evaluateToCopy(oh); // not to void, because void does keep type
	}
	TypeVar p(session.getCurType());
	if (!p) new (space) NullObject();
	else
	{ OList l;
		p->getElemNames(l);
		new (space) ListObject(l);
	}
}


void IndexExpr::evaluateToCopy(void *space)
{
	TypeVar *t;
	{	Object::HolderCP oha;
		a->evaluateToCopy(oha);
		t=session.m_curTypePtr;
		{	oha.protectChilds();
			Object::Holder ohb;	    
			b->evaluateToCopy(ohb);
			oha->indexCopy(ohb,space);
		}
	}
	if (t)
	{	if (!!*t)
			session.m_curTypePtr = &(*t)->m_childType;
		else
			session.m_curTypePtr = 0;
	}
}

void IndexAltExpr::evaluateToCopy(void *space)
{	
	{	Object::HolderCP oha;
		a->evaluateToCopy(oha);
		TypeVar *t=session.m_curTypePtr;
		{	oha.protectChilds();
			Object::Holder ohb;	    
			b->evaluateToCopy(ohb);
			Object *_this=oha;
			while(_this->vtable == &vtable_Ref) _this=M_OBJ;
			int tn=_this->getTypeNum();
			session.m_curTypePtr = 0;
			if ( tn == TOT_Map)
			{ if (t && !!*t)
				{	session.m_curTypePtr = (*t)->getKeyPtr();
				}
				int i=ohb->toInt();
				if (i>=0)
				{	FOREACHM(O_MAP->, { if (!i) { p->key()->duplicateIn(space); goto done; }; i--;} )
				}
				else
				{	FOREACHM_BACK(O_MAP->, { i++; if (!i) { p->key()->duplicateIn(space); goto done; }; } )
				}
			}
			else if ( tn == TOT_List)
			{ int idx=0;
				FOREACH(OList, O_LIST->getList(), i)
				{	if (**i==ohb)
					{	new (space) IntegerObject(idx);
						goto done;
					}
					idx++;
				}
			}
			else if ( tn == TOT_String)
			{	Object *b = ohb->value();
				String as=_this->toString();
				if (b ->getTypeNum() == TOT_RegExp )
				{		List<RE::Match> matches;
						((RegExpObject *)b)->m_expr->match(&matches,as,as.length(),true);
						t = session.m_curTypePtr = 0;
						if (!!matches)
						{
							OList m;
							{	OList regs;
								OList::P regsi(&regs);
								FOREACH(List<String>, matches->m_regs,j)
								{	regsi->prepend(NEW_OBJ StringObject(*j));
									regsi++;
								}
								m.prepend(NEW_OBJ ListObject(regs));
							}
							m.prepend(NEW_OBJ IntegerObject(matches->m_len));
							m.prepend(NEW_OBJ IntegerObject(matches->m_pos));
							new (space) ListObject(m);
							session.m_curTypePtr=&RegExpResultType->m_childType;
							goto done;
						}
						//todo: set type
						//todo: make one function for adding regexp output item
				}		
				else
				{
					String bs=b->toString();
					char *res=strstr((char *)as,(char *)bs);
					if (res)
					{	new (space) IntegerObject(res-as);
						goto done;
					}
				}
			}
			new (space) NullObject(); 
		}
	}
done:
	return;
}

Object *IndexExpr::evaluateToOriginal()
{	
	Object *ao(a->evaluateToOriginal());
	TypeVar *t=session.m_curTypePtr;
	Object *i;
	{	SelfPainter cpa(ao);
		{	Object::Holder ohb;	    
			b->evaluateToCopy(ohb);
			i=ao->index(ohb);
		}
	}
	if (t)
	{	if (!!*t)
			session.m_curTypePtr = &(*t)->m_childType;
		else
			session.m_curTypePtr = 0;
	}
	return i;
}

IFDEBUG( DEFPT(IndexExpr) )
void IndexExpr::toArray(OList::P array) const
{	ADDA(a->toArrayObject(levelTop));
	ADDSTR("[");
	ADDA(b->toArrayObject());
	ADDSTR("]");
}

IFDEBUG( DEFPT(IndexAltExpr) )
void IndexAltExpr::toArray(OList::P array) const
{	ADDA(a->toArrayObject(levelTop));
	ADDSTR("[:");
	ADDA(b->toArrayObject());
	ADDSTR("]");
}


//todo: mapnode always initialized key, maybe also put mapnodes in allocator
void MapExpr::evaluateToCopy(void *space)
{	MapObject *m=new (space) MapObject();
	{	ChildrenPainter cp((Object *)space);
		{
			FOREACH(EList, m_elements, i)
			{
				Object::Holder oha;
				(*i)->evaluateToPersistCopy(oha);
				i++;
				if (!*i)
					m->insertAt((Object *)oha, NullObject::obj());
				else
				{ ChildrenPainter cpa(oha);
					m->insertAt((Object *)oha, (*i)->evaluateToPersistCopy());
				}
			}
		}
	}
}

void MapExpr::evaluateLiteralToCopy(void *space)
{	
	MapObject *m=new (space) MapObject();
	FOREACH(EList, m_elements, i)
	{
		Object::Holder oha;
		(*i)->evaluateToCopy(oha);
		i++;
		if (!*i)
			m->insertAt((Object *)oha, NullObject::obj());
		else {
			m->insertAt((Object *)oha, (*i)->evaluateLiteralToCopy());
		}
	}
}

IFDEBUG( DEFPT(MapExpr) )
void MapExpr::toArray(OList::P array) const
{	ADDSTR("{ ");
	bool first=true;
	FOREACH(EList, m_elements, i)
	{ 
		if (first) { first=false; } else { ADDSTR(", "); }
		OList pair;
		pair.prepend((*i)->toArrayObject());
		i++;
		if (!!*i) {
			pair.end().prepend(NEW_OBJ StringObject(": "));
			pair.end().prepend((*i)->toArrayObject());
		}
		ADDA(NEW_OBJ ListObject(pair));
	}
	ADDSTR(" }");
}

void BlockVarExpr::evaluateToCopy(void *space)
{	
	LOG_EXPR;
	VarValue &vec = ((LocalVarVectorQueue &)*queue).getVarValue(number);
	session.m_curTypePtr = vec.m_typeVarPtr;
	vec.m_value->duplicateIn(space);
}
Object *BlockVarExpr::evaluateToOriginal()
{ 
	LOG_EXPR;
	VarValue &vec = ((LocalVarVectorQueue &)*queue).getVarValue(number);
	session.m_curTypePtr = vec.m_typeVarPtr;
	return vec.m_value;
}
IFDEBUG(void BlockVarExpr::printTyle() const { printf(".%s",(char *)((LocalVarVectorQueue &)*queue).getName(number)); })
IFDEBUG(void SharedLiteralsScopeExpr::printTyle() const { printf("SharedLiterals:"); m_child->printTyle(); })
IFDEBUG(void SharedLiteralExpr::printTyle() const { printf("#%i\n",m_index+1); })
IFDEBUG(void SharedLiteralExprAssigned::printTyle() const { printf("#%i=...\n",m_index+1); })

void BlockVarExpr::toArray(OList::P array) const
{	if (session.m_annotate)
		ADDSTR("/*l*/");
	ADDSTR(((LocalVarVectorQueue &)*queue).getName(number));
}
IFDEBUG(void LocalBlockVarExpr::printTyle() const { BlockVarExpr::printTyle(); })
void LocalBlockVarExpr::toArray(OList::P array) const
{	BlockVarExpr::toArray(array);
	ADDSTR(".");
}
Object *GlobalVarExpr::evaluateToOriginal()
{ 
	LOG_EXPR;
	session.m_curTypePtr = &m_v.getType();
	return m_v.m_value;
}

Object *GlobalVarInitialExpr::evaluateToOriginal()
{ 
	GlobalVariable *g=session.getGlobalVar(m_name);
	g->expr = EPtr(this);
	this->~GlobalVarInitialExpr();
	return (new (this) GlobalVarExpr(*g))->evaluateToOriginal();
}

IFDEBUG(void GlobalVarInitialExpr::printTyle() const { printf("%s",(char *)m_name); })

IFDEBUG(void GlobalVarExpr::printTyle() const { printf("%s",(char *)m_v.getName()); })
void GlobalVarExpr::toArray(OList::P array) const
{	if (session.m_annotate)
		ADDSTR("/*g*/");
	ADDSTR(m_v.getName());
}

void GlobalVarInitialExpr::toArray(OList::P array) const
{	if (session.m_annotate)
		ADDSTR("/*g*/");
	ADDSTR(m_name);
}

void StructIndexingExpr::evaluateToCopy(void *space)
{ 
	{
		Object::HolderCP oha;
		a->evaluateToCopy(oha);
		oha.protectChilds();
		if (updateIndex())
		{	oha->indexCopy(m_index.m_index,space);
		}
		else
		{ new (space) NullObject();
			session.m_curTypePtr = 0;
		}
	}
}

Object *StructIndexingExpr::evaluateToOriginal()
{ 
	LOG_EXPR;
	Object *ao=a->evaluateToOriginal();
	//todo remove more selfpainters?
	if (updateIndex())
		return ao->index(m_index.m_index);
	else { 
		session.m_curTypePtr = 0;
		return NullObject::obj();
	}
}

EPtr CodeComponent::getPredefined() const {
	return EPtr();
}

EPtr ListExpr::getPredefined() const {
	if (!m_elements)
		return session.m_exprEmptyList;
	return EPtr();
}

EPtr MapExpr::getPredefined() const {
	if (!m_elements)
		return session.m_exprEmptyMap;
	return EPtr();
}

bool CodeComponent::isLValue() const { return false; }
bool DeReferenceExpr::isLValue() const { return a->isLValue(); }
bool ParamExpr::isLValue() const { return true; }
bool ArgumentExpr::isLValue() const { return false; } // not for argumentList
bool IteratorVarExpr::isLValue() const { return true; } // not for IteratorKeyVarExpr!
bool NamedIteratorVarExpr::isLValue() const { return true; } // not for key!

int CodeComponent::levelLeft() const { return levelBottom; }
int CodeComponent::levelRight() const { return levelBottom; }
int MultiStat::levelLeft() const { return levelTop; }
int ConstExpr::levelLeft() const
{ 
	int t=m_val->getTypeNum();
	return t==TOT_Expr ? levelTop : levelBottom;//t==TOT_Null || t==TOT_List || t==TOT_Map ? levelBottom : (t==TOT_Expr ? levelModify : 0);
}

bool Statement::isExpr() const { return false; }
bool MultiStat::isExpr() const { return false; }
bool Expr::isExpr() const { return true; }
bool SwitchOnExpr::isExpr() const {
	FOREACH(EList, m_choices, i)
		if(!(*i)->isExpr())
			return false;
	return true;
}

void TypeSelectionExpr::toArray(OList::P array) const
{
	ADDA(bracketize(m_func->toArrayObject(m_typeFuncs)));
	if (!!a) ADDA(a->toArrayObject(levelTop));
}

Object *ParamExpr::evaluateToOriginal()
{ 
	Object *ao=ArgumentListExpr::evaluateToOriginal();
	if (updateIndex()) { 
		return ao->index(m_index.m_index);
	}
	else {
		session.m_curTypePtr = 0;
		return NullObject::obj();
	}
}

IFDEBUG( DEFPT(TypeSelectionExpr) )
IFDEBUG(
void ParamExpr::printTyle() const { printf("%s", (char *)m_index.m_name);}
)
void ParamExpr::toArray(OList::P array) const
{	if (session.m_annotate)
		ADDSTR("/*p*/");
	ADDSTR(m_index.m_name);
}

IFDEBUG( DEFPT(IteratorVarExpr) )
IFDEBUG( DEFPT(MultiStat) )
IFDEBUG( DEFPT(ParamListAssignmentExpr) )

void NamedIteratorVarExpr::toArray(OList::P array) const
{	if (session.m_annotate)
		ADDSTR("/*i*/");
	ADDSTR(((NamedIteratorVarsScope &)*m_scope).m_name);
}

void NamedIteratorKeyVarExpr::toArray(OList::P array) const
{	if (session.m_annotate)
		ADDSTR("/*i*/");
	ADDSTR(((NamedIteratorVarsScope &)*m_scope).m_keyName);
}

IFDEBUG( 
void StructIndexingExpr::printTyle() const { a->printTyle(); printf(" . %s", (char *)m_index.m_name);}
)
void StructIndexingExpr::toArray(OList::P array) const
{	ADDA(a->toArrayObject(levelTop));
	ADDSTR(".");
	ADDSTR(m_index.m_name);
}

void StructIndexingNumberExpr::evaluateToCopy(void *space)
{ 
	a->evaluateToVoid(); //necessary because this can change index
	if (updateIndex())
	{ new (space)  IntegerObject(m_index.m_index);
	}
	else
		new (space) NullObject();
}

void TypeSelectCarrier::assignTypeVars() const
{
	for (List<TypeFunc>::P i(&m_typeFuncs); !!*i;) {
		bool once=false;
		(*i)->evaluate(once);
		if(once)
			i->removeone();
		else
			i++;
	}
}
Object *TypeSelectionExpr::evaluateToOriginal()
{ 
	assignTypeVars();

	if (!!a)  // assignment to variables:
	{ 
		Object *res = a->evaluateToOriginal();
		session.setCurType(m_func->evaluate());
		return res;
	}
	else
	{ session.m_curTypePtr = 0;
		return NullObject::obj();
	}
}
void TypeSelectionExpr::evaluateToCopy(void *space)
{ 
	assignTypeVars();
	if (!!a) 
	{ 
		a->evaluateToCopy(space);
		session.setCurType(m_func->evaluate());
	}
	else
	{	m_func->evaluate(); // can also be, and probably is, a type assignment
		new (space) NullObject();
	}
}
// no TypeSelectionExpr::evaluateToVoid(), because we cannot evaluate 'a' to void anyway

void StructLengthExpr::toArray(OList::P array) const
{
	ADDA(a->toArrayObject(levelTop));
	ADDSTR(".@");
}

void StructLengthExpr::evaluateToCopy(void *space)
{
	a->evaluateToVoid();
	TypeVar t(session.getCurType());
	new (space) IntegerObject (!!t?t->m_elems.length():0);
	session.m_curTypePtr = 0;
}

bool StructIndexingExpr::updateIndex()
{
	switch(m_index.update())
	{
	case 0: return true;
	case 1: session.reportRuntimeError(String("Cannot find element '")+m_index.m_name+"' in '"+toTyle()+"'."); break;
	case 2: session.reportRuntimeError(String("Indexing of non-struct in '")+toTyle()+"'."); break;
	}
	return false;
}

bool ParamExpr::updateIndex()
{
	if (m_index.update())
	{	session.reportRuntimeError(String("Cannot find parameter '")+m_index.m_name+"'."); return false;
	}
	return true;
}

IFDEBUG( DEFPT(StructIndexingNumberExpr) )
void StructIndexingNumberExpr::toArray(OList::P array) const
{	
	ADDA(a->toArrayObject(levelTop));
	ADDSTR(".@");
	ADDSTR(m_index.m_name);
}

void NamedIteratorVarAssignmentExpr::initEval() const
{
	assignTypeVars();
	if(!!m_func)
		*session.getStackVar(((NamedIteratorVarsScope &)*m_scope).m_depth).m_typePtr = m_func->evaluate();
	session.execPush(m_scope);
}

void NamedIteratorVarAssignmentExpr::evaluateToCopy(void *space)
{
	initEval(); 
	a->evaluateToCopy(space);
	session.execPop();	
}
void NamedIteratorVarAssignmentExpr::evaluateToVoid()
{ 
	initEval();
	a->evaluateToVoid();
	session.execPop();	
}

void ParamListAssignmentExpr::initEval() const
{
	assignTypeVars();
	TypeVar p(((ParamListScope &)*m_scope).m_type);
	_ASSERT(session.m_funcLevel==0);
	if (! p->isEmpty() )
		*session.getStackVar(0).m_typePtr = p;
	session.execPush(m_scope);
}

void ParamListAssignmentExpr::evaluateToCopy(void *space)
{ 
	initEval();
	a->evaluateToCopy(space);
	session.execPop();
}
void ParamListAssignmentExpr::evaluateToVoid()
{ 
	initEval();
	a->evaluateToVoid();
	session.execPop();
}

bool CodeComponent::isDynamic() const {
	return true;
}

bool ConstExpr::isDynamic() const {
	return false;
}

bool CodeComponent::isContainer(bool &inARef) const {
	inARef = false;
	return false;
}

bool ListExpr::isContainer(bool &inARef) const {
	inARef = false;
	return true;
}

bool MapExpr::isContainer(bool &inARef) const {
	inARef = false;
	return true;
}

bool ReferenceExpr::isContainer(bool &inARef) const {
	inARef = true;
	return true;
}

bool CodeComponent::consolidateSharedLiterals(vector<EPtr> &sharedLiterals, bool inARef) const {
	return false;
}

bool SharedLiteralExpr::consolidateSharedLiterals(vector<EPtr> &sharedLiterals, bool inARef) {
	if (!inARef)
		throw("Referenced shared literal should be contained in a reference ('&...')");
	return true;
}

bool SharedLiteralExprAssigned::consolidateSharedLiterals(vector<EPtr> &sharedLiterals, bool inARef) {
	if ((unsigned)m_index>=sharedLiterals.size()) {
		sharedLiterals.resize(m_index+1);
	}
	sharedLiterals[m_index]=m_value;
	return true;
}

// more sharing
void NamedIteratorVarAssignmentExpr::toArray(OList::P array) const
{
	{
		OList a;
		PREPENDSTR_A(" | ",a);
		PREPENDSTR_A(((NamedIteratorVarsScope &)*m_scope).m_name,a);
		List<TypeFunc>::P pfs(&m_typeFuncs);
		Object *ko=!!m_keyFunc ? m_keyFunc->toArrayObject(100,pfs) : 0;
		if (!!m_func)
			PREPENDA_A(bracketize(m_func->toArrayObject(100,pfs)),a);
		bool hasKeyName=!!((NamedIteratorVarsScope &)*m_scope).m_keyName; 
		if (hasKeyName) {
			PREPENDSTR_A(": ",a);
			PREPENDSTR_A(((NamedIteratorVarsScope &)*m_scope).m_name,a);
		}
		if (ko) {
			if (!hasKeyName)
				PREPENDSTR_A(": ",a);
			PREPENDA_A(bracketize(ko),a);
		}
		PREPENDSTR_A("| ",a);
		ADDA(NEW_OBJ ListObject(a));
	}
	ADDA(a->toArrayObject(levelProcedure));
}
void ParamListAssignmentExpr::toArray(OList::P array) const
{	
	{	
		OList a;
		PREPENDSTR_A(" |",a);
		PREPENDA_A(((ParamListScope &)*m_scope).m_type->elemsToArrayObject(m_typeFuncs),a);
		PREPENDSTR_A("| ",a);
		ADDA(NEW_OBJ ListObject(a));
	}
	ADDA(a->toArrayObject(levelProcedure));
}

IFDEBUG(void NamedIteratorVarAssignmentExpr::printTyle() const { printf("spa\n"); })

IFDEBUG( DEFPT(ClosureVarExpr) )
Object *ClosureVarExpr::evaluateToOriginal() 
{ 
	LOG_EXPR;
	VarValue &v=session.m_curClosures->m_vars[m_index];
	session.m_curTypePtr = v.m_typeVarPtr;
	return v.m_value;
}
void ClosureVarExpr::toArray(OList::P array) const
{
	if (session.m_annotate)
		ADDSTR("/*c*/");
	ADDSTR(((ClosureScope &)*session.m_curClosures->m_scope).m_closures[m_index].name);
}
IFDEBUG(void ClosuredExprExpr::printTyle() const { printf("?closure? "); a->printTyle(); } )

void ClosuredExprExpr::toArray(OList::P array) const
{
	//todo: can this code be removed? or used in finishmakeexpr?
	ADDSTR("? ");
	ClosureBinding *ocs=session.m_curClosures;
	ClosureBindingPtr p;
	new (p) ClosureBinding(m_scope);
	session.m_curClosures=p;
	ADDA(a->toArrayObject(levelModify));
	session.m_curClosures = ocs;
}

void ClosuredExprExpr::evaluateToCopy(void *space) ///.
{ 
	ClosureBindingPtr p;
	new (p) ClosureBinding(a,m_scope);
	new (space) ClosuredExprObject(p );
}

} // namespace

